// Copyright (c) 2012 Tobias Reimann
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "stdafx.h"
#include "AtisMaker.h"
#include "Helper.h"
#include "EuroScopePlugIn.h"

#include<sstream>

using namespace std;

AtisMaker::AtisMaker()
{
	//set default values
	shortTerms = true;
	specials = true;
	runwayDetails = true;

	freeText = "";
	closedTaxiways = "";
	ApproachType = "ILS";
	IlsCalibration = "";

	//frequencies
	departureFrequency = "";
	clearanceFrequency = "";
	groundFrequency = "";

	space = "[ ]";
}

AtisMaker::~AtisMaker()
{
	//clean up
}

string AtisMaker::Generate(string atisairport, string atiscode, string metar, string arrrwy, string deprwy)
{
	AtisAirport = atisairport;
	stringstream ss;
	ss << "[" << ParseAirportName(atisairport) << "]";
	ss << "[INFORMATION][" << ParseAtisLetter(atiscode) << "]";
	ss << space;
	//metar
	ss << "[MET REPORT TIME]" << ParseDate(metar) << space;
	ss << ParseRunwayInfo(atisairport, arrrwy, deprwy);
	ss << ParseApronInfo(closedTaxiways, departureFrequency, clearanceFrequency, groundFrequency);
	ss << ((shortTerms) ? "[TRL]" : "[TRANSITION LEVEL]") << ParseTransitionLevel(ParseQNH(metar)) << space;
	ss << ParseParallelRunwayWarning(atisairport, arrrwy, deprwy);
	ss << ParseWind(metar);
	ss << ParseVisibility(metar);
	ss << ParsePrecip(metar);
	ss << ParseClouds(metar);
	ss << ParseVerticalVisibility(metar);
	ss << ParseTemperature(metar);
	ss << "[QNH]" << ParseQNH(metar) << "[hPa]" << space;
	ss << ParseTrend(metar);
	ss << "[INFORMATION][" << ParseAtisLetter(atiscode) << "][OUT]" << space << space << space;
	//AfxMessageBox ( ApproachType.c_str() ) ;
	return ss.str();
}

string AtisMaker::ParseAirportName(string icao)
{
	if(icao == "EDDT") return "BERLIN TEGEL";
	if(icao == "EDDB") return "BERLIN SCHOENEFELD";
	if(icao == "EDDC") return "DRESDEN";
	if(icao == "EDDE") return "ERFURT";
	if(icao == "EDDP") return "LEIPZIG HALLE";
	return icao;
}

string AtisMaker::ParseAtisLetter(string release)
{
	if(release == "A") return "ALPHA";
	if(release == "B") return "BRAVO";
	if(release == "C") return "CHARLIE";
	if(release == "D") return "DELTA";
	if(release == "E") return "ECHO";
	if(release == "F") return "FOXTROT";
	if(release == "G") return "GOLF";
	if(release == "H") return "HOTEL";
	if(release == "I") return "INDIA";
	if(release == "J") return "JULIET";
	if(release == "K") return "KILO";
	if(release == "L") return "LIMA";
	if(release == "M") return "MIKE";
	if(release == "N") return "NOVEMBER";
	if(release == "O") return "OSCAR";
	if(release == "P") return "PAPA";
	if(release == "Q") return "QUEBEC";
	if(release == "R") return "ROMEO";
	if(release == "S") return "SIERRA";
	if(release == "T") return "TANGO";
	if(release == "U") return "UNIFORM";
	if(release == "V") return "VICTOR";
	if(release == "W") return "WHISKEY";
	if(release == "X") return "X-RAY";
	if(release == "Y") return "YANKEE";
	if(release == "Z") return "ZULU";
	return release;
}

string AtisMaker::ParseRunwayInfo(string atisairport, string arr, string dep)
{
	int numberActiveRunways = 0;
	int numberDepartureRunways = 0;
	int numberArrivalRunways = 0;

	string ActiveRWY[4] = { "", "", "", "" };
	string ArrivalRWY[4];
	string DepartureRWY[4];
	string tmp;

	h.ReplaceAll(arr, ",", " ");
	h.ReplaceAll(dep, ",", " ");

	istringstream iss1(arr);
	while(iss1)
	{
		tmp = "";
		iss1 >> tmp;
		if(tmp != "")
		{
			ArrivalRWY[numberArrivalRunways] = tmp;
			numberArrivalRunways++;
			if(!h.Contains(ActiveRWY, tmp, numberActiveRunways))
			{
				ActiveRWY[numberActiveRunways] = tmp;
				numberActiveRunways++;
			}
		}
	}
	
	istringstream iss2(dep);
	while(iss2)
	{
		tmp = "";
		iss2 >> tmp;
		if(tmp != "")
		{
			DepartureRWY[numberDepartureRunways] = tmp;
			numberDepartureRunways++;
			if(!h.Contains(ActiveRWY, tmp, numberActiveRunways))
			{
				ActiveRWY[numberActiveRunways] = tmp;
				numberActiveRunways++;
			}
		}
	}

	stringstream pisten;
	if(ApproachType == "ILS")
	{
		pisten << "[EXPECT ILS APPROACH]";
	}
	else if(ApproachType == "NDB")
	{
		pisten << "[EXPECT NDB-DME APPROACH]";
	}
	else if(ApproachType == "VOR")
	{
		pisten << "[EXPECT VOR-DME APPROACH]";
	}
	else if(ApproachType == "LOC")
	{
		pisten << "[EXPECT LOC-DME APPROACH]";
	}
	else if(ApproachType == "VIS")
	{
		pisten << "[EXPECT VISUAL APPROACH]";
	}

	if(numberActiveRunways == 1)
	{
		pisten << "[RUNWAY IN USE] " << ActiveRWY[0];
	}
	else if (numberActiveRunways > 1)
	{
		if(numberArrivalRunways > 0)
		{
			pisten << "[RUNWAY]" << ArrivalRWY[0];
			for(int i = 1; i < numberArrivalRunways; i++)
			{
				if(i + 1 == numberArrivalRunways)
				{
					pisten << "[OR]";
				}
				else if(i > 0)
				{
					pisten << " ";
				}
				pisten << ArrivalRWY[i];
			}
			pisten << space;
		}
		pisten << "[RUNWAYS IN USE]";
		for(int i = 0; i < numberActiveRunways; i++)
		{
			if(i + 1 == numberActiveRunways)
			{
				pisten << "[AND]";
			}
			else if(i > 0)
			{
				pisten << " ";
			}
			pisten << ActiveRWY[i];
		}
	}
	pisten << space;
	if(runwayDetails && atisairport == "EDDT")
	{
		if(h.Contains(DepartureRWY, "26L", numberDepartureRunways) && h.Contains(DepartureRWY, "26R", numberDepartureRunways) ) pisten << "[FOR DEPARTURE EXPECT][RUNWAY]26L" << space << "[RUNWAY]26R[ON REQUEST]" << space;
		if(h.Contains(DepartureRWY, "08L", numberDepartureRunways) && h.Contains(DepartureRWY, "08R", numberDepartureRunways) ) pisten << "[FOR DEPARTURE EXPECT][RUNWAY]08R" << space << "[RUNWAY]08L[ON REQUEST]" << space;
	}

	if(IlsCalibration != "") pisten << "[ILS]" << IlsCalibration << "[ON MAINTENANCE]" << space << "[DISREGARD ALL SIGNALS]" << space << "[ILS][CALIBRATION][RUNWAY]" << IlsCalibration << "[IN PROGRESS]" << space;

	return pisten.str();;
}

string AtisMaker::ParseApronInfo(string closedTaxiways, string departureFrequency, string clearanceFrequency, string groundFrequency)
{
	stringstream ss;
	if( closedTaxiways != "" ) ss << closedTaxiways << space;
	if(clearanceFrequency != "") ss << "[CLEARANCE DELIVERY ON FREQUENCY]" << clearanceFrequency << space;
	if(groundFrequency != "") ss << "[GROUND ON FREQUENCY]" << groundFrequency << space;
	if(departureFrequency != "") ss << "[DEPARTURE FREQUENCY]" << departureFrequency << space;
	return ss.str();
}

string AtisMaker::ParseDate(string metar)
{
	istringstream iss(metar);
	string element;
	iss >> element; // icao
	iss >> element; // date
	string date(element,2, 4);
	return date;
}

string AtisMaker::ParseTransitionLevel(string qnh_s)
{
	int qnh = atoi(qnh_s.c_str());
	if(qnh > 1050) return("50");
	if(qnh >= 1014 && qnh <= 1050) return ("60");
	if(qnh >= 978 && qnh <= 1013) return("70");
	if(qnh <= 977) return("80");
}

string AtisMaker::ParseQNH(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element.length() == 5 && (element.find("Q") == 0 || element.find("A") == 0))
		{
			int value = atoi(element.substr(1,4).c_str());
			if(element.find("A") == 0) value *= 0.3386389;
			ss << value;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParseWind(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;

		if(element.length() >= 7 && element.find("KT") != -1)
		{
			string wdir = element.substr(0,3);
			string wspd = element.substr(3,2);

			string wgust = "";

			if(element.find("G") != -1)
			{
				wgust = element.substr(element.find("G") + 1, 2);				
			}
			ss << "[WIND]";
			ss << ((wspd == "00") ? "[CALM]" : ((wdir == "VRB") ? "[VARIABLE]" : wdir + "[DEGREES]"));
			ss << atoi(wspd.c_str()) << "" << ((wspd == "01") ? "[KNOT]" : "[KNOTS]");
			if(wgust != "") ss << "[GUSTS UP TO]" << wgust << "[KNOTS]";

			iss >> element;
			if(element.length() == 7 && element.find("V") != -1)
			{
				//variation
				//123V234
			}
			ss << space;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParseVisibility(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element.length() == 4)
		{
			int value = atoi(element.c_str());
			if(value == 0 && element != "0000") continue; // not a number
			ss << "[VISIBILITY]";
			if(element == "0000")
			{
				ss << "[LESS THAN]50[METERS]";
			}
			else if(element == "9999")
			{
				ss << "[MORE THAN]10[KM]";
			}
			else
			{
				if(value >= 5000)
				{
					value /= 1000;
					ss << value << "[KM]";
				}
				else
				{
					ss << value << "[METERS]";
				}
			}
			ss << space;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParsePrecip(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;

	bool started = false;

	while(iss)
	{
		iss >> element;
		if((h.Endswith(element, "DZ") || h.Endswith(element, "RA") || h.Endswith(element, "SN") || h.Endswith(element, "GR") || h.Endswith(element, "SQ") || h.Endswith(element, "GS") || h.Endswith(element, "SG") || h.Endswith(element, "IC") || h.Endswith(element, "PE") || h.Endswith(element, "BR") || h.Endswith(element, "FG") || h.Endswith(element, "FU") || h.Endswith(element, "HZ") || h.Endswith(element, "VA") || h.Endswith(element, "DU") || h.Endswith(element, "SA") || h.Endswith(element, "SS") || h.Endswith(element, "DS") || h.Endswith(element, "FC"))
			&& (element.length() < 4 || h.MiddlePart(element, "MI") || h.MiddlePart(element, "BC") || h.MiddlePart(element, "DR") || h.MiddlePart(element, "BL") || h.MiddlePart(element, "TS") || h.MiddlePart(element, "FZ") || h.MiddlePart(element, "RE") || h.MiddlePart(element, "DZ") || h.MiddlePart(element, "RA") || h.MiddlePart(element, "SN") || h.MiddlePart(element, "GR") || h.MiddlePart(element, "SQ") || h.MiddlePart(element, "GS") || h.MiddlePart(element, "SG") || h.MiddlePart(element, "IC") || h.MiddlePart(element, "PE") || h.MiddlePart(element, "BR") || h.MiddlePart(element, "FG") || h.MiddlePart(element, "FU") || h.MiddlePart(element, "HZ") || h.MiddlePart(element, "VA") || h.MiddlePart(element, "DU") || h.MiddlePart(element, "SA") || h.MiddlePart(element, "SS") || h.MiddlePart(element, "DS") || h.MiddlePart(element, "FC") || h.MiddlePart(element, "VC") || h.MiddlePart(element, "SH")))
		{
			if(!started) { ss << "[PRESENT WEATHER]"; started = true; }
			if(element.find("+") == 0) ss << "[HEAVY]";
			if(element.find("-") == 0) ss << "[LIGHT]";
			if(element.length() > 3)
			{
				if(h.MiddlePart(element, "MI")) ss << "[SHALLOW]";
				if(h.MiddlePart(element, "BC")) ss << "[PATCHES][OF]";
				if(h.MiddlePart(element, "DR")) ss << "[DRIFTING]";
				if(h.MiddlePart(element, "BL")) ss << "[BLOWING]";
				if(h.MiddlePart(element, "TS")) ss << "[THUNDERSTORM][WITH]";
				if(h.MiddlePart(element, "FZ")) ss << "[FREEZING]";
				if(h.MiddlePart(element, "RE")) ss << "[RECENT]";
				//DOPPELT
				if(h.MiddlePart(element, "DZ")) ss << "[DRIZZLE][AND]";
				if(h.MiddlePart(element, "RA")) ss << "[RAIN][AND]";
				if(h.MiddlePart(element, "SN")) ss << "[SNOW][AND]";
				if(h.MiddlePart(element, "GR")) ss << "[HAIL][AND]";
				if(h.MiddlePart(element, "SQ")) ss << "[SQUALLS][AND]";
				if(h.MiddlePart(element, "GS")) ss << "[SMALL][HAIL][AND]";
				if(h.MiddlePart(element, "SG")) ss << "[SMALL][GRAINS][AND]";
				if(h.MiddlePart(element, "IC")) ss << "[DIAMOND][DUST][AND]";
				if(h.MiddlePart(element, "PE")) ss << "[ICE][PELLETS][AND]";
				if(h.MiddlePart(element, "BR")) ss << "[MIST][AND]";
				if(h.MiddlePart(element, "FG")) ss << "[FOG][AND]";
				if(h.MiddlePart(element, "FU")) ss << "[SMOKE][AND]";
				if(h.MiddlePart(element, "HZ")) ss << "[HAZE][AND]";
				if(h.MiddlePart(element, "VA")) ss << "[VOLCANIC][ASH][AND]";
				if(h.MiddlePart(element, "DU")) ss << "[WIDESPREAD][DUST][AND]";
				if(h.MiddlePart(element, "SA")) ss << "[SAND][AND]";
				if(h.MiddlePart(element, "SS")) ss << "[SANDSTORM][AND]";
				if(h.MiddlePart(element, "DS")) ss << "[DUSTSTORM][AND]";
				if(h.MiddlePart(element, "FC")) ss << "[FUNNEL][CLOUD][AND]";
			}
			if(h.Endswith(element, "DZ")) ss << "[DRIZZLE]";
			if(h.Endswith(element, "RA")) ss << "[RAIN]";
			if(h.Endswith(element, "SN")) ss << "[SNOW]";
			if(h.Endswith(element, "GR")) ss << "[HAIL]";
			if(h.Endswith(element, "SQ")) ss << "[SQUALLS]";
			if(h.Endswith(element, "GS")) ss << "[SMALL][HAIL]";
			if(h.Endswith(element, "SG")) ss << "[SMALL][GRAINS]";
			if(h.Endswith(element, "IC")) ss << "[DIAMOND][DUST]";
			if(h.Endswith(element, "PE")) ss << "[ICE][PELLETS]";
			if(h.Endswith(element, "BR")) ss << "[MIST]";
			if(h.Endswith(element, "FG")) ss << "[FOG]";
			if(h.Endswith(element, "FU")) ss << "[SMOKE]";
			if(h.Endswith(element, "HZ")) ss << "[HAZE]";
			if(h.Endswith(element, "VA")) ss << "[VOLCANIC][ASH]";
			if(h.Endswith(element, "DU")) ss << "[WIDESPREAD][DUST]";
			if(h.Endswith(element, "SA")) ss << "[SAND]";
			if(h.Endswith(element, "SS")) ss << "[SANDSTORM]";
			if(h.Endswith(element, "DS")) ss << "[DUSTSTORM]";
			if(h.Endswith(element, "FC")) ss << "[FUNNEL][CLOUD]";
			if(element.length() > 3)
			{
				if(h.MiddlePart(element, "SH")) ss << "[SHOWERS]";
				if(h.MiddlePart(element, "VC")) ss << "[IN THE VICINITY]";
			}
			ss << space;
		}
	}
	
	return ss.str();
}

string AtisMaker::ParseClouds(string metar)
{
	bool started = false;
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element == "CAVOK")
		{
			ss << ((shortTerms) ? "[CAVOK]" : "[CLOUDS AND VISIBILITY OKAY]") << space;
			break;
		}
		if(element == "NSC")
		{
			ss << "[NO SIGNIFICANT CLOUDS]" << space;
			break;
		}
		if(element.length() >= 6)
		{
			int value = atoi(element.substr(3,3).c_str()) * 100;
			if(element.find("FEW") == 0 && value < 10000)
			{
				if(!started) { ss << "[CLOUDS]"; started = true; }
				ss << "[FEW]{" << value << "}[FT]" << space;
				continue;
			}
			if(element.find("SCT") == 0 && value < 10000)
			{
				if(!started) { ss << "[CLOUDS]"; started = true; }
				ss << "[SCATTERED]{" << value << "}[FT]" << space;
				continue;
			}
			if(element.find("BKN") == 0 && value < 10000)
			{
				if(!started) { ss << "[CLOUDS]"; started = true; }
				ss << "[BROKEN]{" << value << "}[FT]" << space;
				continue;
			}
			if(element.find("OVC") == 0 && value < 10000)
			{
				if(!started) { ss << "[CLOUDS]"; started = true; }
				ss << "[OVERCAST]{" << value << "}[FT]" << space;
				continue;
			}
		}
	}
	return ss.str();
}

string AtisMaker::ParseVerticalVisibility(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element == "VV///")
		{
			ss << "[NO VERTICAL VISIBILITY]" << space;
			break;
		}
		else if(element.length() == 5 && element.find("VV") == 0)
		{
			int value = atoi(element.substr(2,3).c_str()) * 100;
			ss << "[VERTICAL VISIBILITY]" << value << "[FT]" << space;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParseTemperature(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element.length() >= 5 && element.length() <=7 && element.find("/") != -1 && element.find("VV") == -1)
		{
			int c = 0;
			ss << "[TEMPERATURE]";

			if(element.find("M") == 0)
			{
				ss << "[MINUS]";
				c++;
			}
			ss << atoi(element.substr(c, 2).c_str()) << space;
			ss << "[DEWPOINT]";
			c = element.find("/") + 1;
			if(element.find("M", c) == c)
			{
				ss << "[MINUS]";
				c++;
			}
			ss << atoi(element.substr(c, 2).c_str()) << space;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParseTrend(string metar)
{
	istringstream iss(metar);
	ostringstream ss;
	string element;
	while(iss)
	{
		iss >> element;
		if(element == "NOSIG")
		{
			ss << ((shortTerms) ? "[TREND][NOSIG]" : "[TREND][NO SIGNIFICANT CHANGES]") << space;
			break;
		}
	}
	return ss.str();
}

string AtisMaker::ParseParallelRunwayWarning(string atisairport, string arrrwy, string deprwy)
{
	if(specials && atisairport == "EDDT")
	{
		//(in_array("26L",$dep) && in_array("26R",$arr))
		//			|| (in_array("26R",$dep) && in_array("26L",$arr))
		//			|| (in_array("08R",$dep) && in_array("08L",$arr))
		//			|| (in_array("08L",$dep) && in_array("08R",$arr))
		return "[USE CAUTION AFTER LANDING, SHORT DISTANCE BETWEEN RUNWAYS, EXPECT TO STOP BEFORE PARALLEL RUNWAY]" + space;
	}
	return "";
}


